from datetime import datetime, date, timedelta
from pathlib import Path
from typing import List, Optional

from httpserverutil.logger.grouped_logger import LogWriter
from httpserverutil.logger.abstract_logger import LOG_LEVEL_NAMES


LOG_LEVEL_FOLDERS = [None, "DBG", "INF", "WRN", "ERR", "FTL"]


class FileLogWriter(LogWriter):
    root: Path                  # 主目录
    date_last_write: date       # 上次log的日期
    date_str: str               # 缓存当前日期
    keep_days: Optional[int]    # log保留几天

    def __init__(self, root: Path, keep_days: Optional[int] = None):
        self.root = root
        self.date_last_write = date.fromtimestamp(0)
        self.keep_days = keep_days

    def log(self, level: int, msg: str, now: datetime, path: List[str]):
        now = now.astimezone(None)
        current_date = now.date()

        # is_new_date = 距离上次打log日期是否发生变化
        if current_date != self.date_last_write:
            self.date_last_write = current_date
            self.date_str = current_date.strftime("%Y-%m-%d")
            is_new_date = True
        else:
            is_new_date = False

        time_str = now.time().isoformat(timespec="milliseconds")
        line = f"[{time_str}][{LOG_LEVEL_NAMES[level]}] {msg}\n"
        for log_level in range(1, level + 1):
            level_str = LOG_LEVEL_FOLDERS[log_level]
            file_dir = Path(self.root, self.date_str, level_str, *path[:-1])
            file_dir.mkdir(parents=True, exist_ok=True)
            file_path = file_dir / (path[-1] + ".log")
            with file_path.open(mode="a", encoding="utf-8") as stream:
                stream.writelines([line])

        if is_new_date:
            self._roll_out_old_logs()

    def _roll_out_old_logs(self):
        """滚动掉旧的log
        """

        if self.keep_days is None:
            return

        too_old_if_before = self.date_last_write - timedelta(days=self.keep_days)
        dir_to_delete: List[Path] = []
        for sub_dir in self.root.iterdir():
            if not sub_dir.is_dir():
                continue

            try:
                dir_date = datetime.strptime(sub_dir.name, "%Y-%m-%d").date()
            except:
                continue

            if dir_date < too_old_if_before:
                dir_to_delete.append(sub_dir)

        for sub_dir in dir_to_delete:
            rmdir_recursively(sub_dir)


def rmdir_recursively(path: Path):
    if path.is_dir():
        for item in path.iterdir():
            rmdir_recursively(item)
        path.rmdir()
    else:
        path.unlink()
